package com.espian.showcaseview;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Region.Op;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.Button;
import android.widget.RelativeLayout;
import com.espian.showcaseview.actionbar.ActionBarViewWrapper;
import com.espian.showcaseview.actionbar.reflection.BaseReflector;
import com.espian.showcaseview.anim.AnimationUtils;
import com.espian.showcaseview.anim.AnimationUtils.AnimationEndListener;
import com.espian.showcaseview.anim.AnimationUtils.AnimationStartListener;
import com.espian.showcaseview.drawing.ClingDrawer;
import com.espian.showcaseview.drawing.ClingDrawerImpl;
import com.espian.showcaseview.drawing.TextDrawer;
import com.espian.showcaseview.drawing.TextDrawerImpl;
import com.espian.showcaseview.targets.PointTarget;
import com.espian.showcaseview.targets.Target;
import com.espian.showcaseview.targets.ViewTarget;
import com.espian.showcaseview.utils.Calculator;
import com.espian.showcaseview.utils.PointAnimator;
import com.github.espiandev.showcaseview.R;
import com.nineoldandroids.animation.Animator;
/**
* A view which allows you to showcase areas of your app with an explanation.
*/
public class ShowcaseView extends RelativeLayout
implements View.OnClickListener, View.OnTouchListener {
public static final int TYPE_NO_LIMIT = 0;
public static final int TYPE_ONE_SHOT = 1;
public static final int INSERT_TO_DECOR = 0;
public static final int INSERT_TO_VIEW = 1;
public static final int ITEM_ACTION_HOME = 0;
public static final int ITEM_TITLE = 1;
public static final int ITEM_SPINNER = 2;
public static final int ITEM_ACTION_ITEM = 3;
public static final int ITEM_ACTION_OVERFLOW = 6;
protected static final String PREFS_SHOWCASE_INTERNAL = "showcase_internal";
public static final int INNER_CIRCLE_RADIUS = 94;
private static final Interpolator INTERPOLATOR = new AccelerateDecelerateInterpolator();
private int mShowcaseX = -1;
private int mShowcaseY = -1;
private float mShowcaseRadius = -1;
private float mMetricScale = 1.0f;
// private float legacyShowcaseX = -1;
// private float legacyShowcaseY = -1;
private boolean mIsRedundant = false;
private boolean mHasCustomClickListener = false;
private ConfigOptions mOptions;
private int mBackgroundColor;
private View mHandy;
private final Button mEndButton;
OnShowcaseEventListener mEventListener = OnShowcaseEventListener.NONE;
private boolean mAlteredText = false;
private final String mButtonText;
private float mScaleMultiplier = 1f;
private TextDrawer mTextDrawer;
private ClingDrawer mShowcaseDrawer;
public static final Target NONE = new Target() {
@Override
public Point getPoint() {
return null;
}
};
private boolean mHasNoTarget = false;
protected ShowcaseView(Context context) {
this(context, null, R.styleable.CustomTheme_showcaseViewStyle);
}
protected ShowcaseView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// Get the attributes for the ShowcaseView
final TypedArray styled = context.getTheme()
.obtainStyledAttributes(attrs, R.styleable.ShowcaseView, R.attr.showcaseViewStyle,
R.style.ShowcaseView);
mBackgroundColor = styled
.getInt(R.styleable.ShowcaseView_sv_backgroundColor, Color.argb(128, 80, 80, 80));
int showcaseColor = styled
.getColor(R.styleable.ShowcaseView_sv_showcaseColor, Color.parseColor("#33B5E5"));
int titleTextAppearance = styled
.getResourceId(R.styleable.ShowcaseView_sv_titleTextAppearance,
R.style.TextAppearance_ShowcaseView_Title);
int detailTextAppearance = styled
.getResourceId(R.styleable.ShowcaseView_sv_detailTextAppearance,
R.style.TextAppearance_ShowcaseView_Detail);
mButtonText = styled.getString(R.styleable.ShowcaseView_sv_buttonText);
styled.recycle();
mMetricScale = getContext().getResources().getDisplayMetrics().density;
mEndButton = (Button) LayoutInflater.from(context).inflate(R.layout.showcase_button, null);
mShowcaseDrawer = new ClingDrawerImpl(getResources(), showcaseColor);
// TODO: This isn't ideal, ClingDrawer and Calculator interfaces should be separate
mTextDrawer = new TextDrawerImpl(mMetricScale, mShowcaseDrawer);
mTextDrawer.setTitleStyling(context, titleTextAppearance);
mTextDrawer.setDetailStyling(context, detailTextAppearance);
ConfigOptions options = new ConfigOptions();
options.showcaseId = getId();
setConfigOptions(options);
init();
}
private void init() {
setHardwareAccelerated(true);
boolean hasShot = getContext()
.getSharedPreferences(PREFS_SHOWCASE_INTERNAL, Context.MODE_PRIVATE)
.getBoolean("hasShot" + getConfigOptions().showcaseId, false);
if (hasShot && mOptions.shotType == TYPE_ONE_SHOT) {
// The showcase has already been shot once, so we don't need to do anything
setVisibility(View.GONE);
mIsRedundant = true;
return;
}
mShowcaseRadius = mMetricScale * INNER_CIRCLE_RADIUS;
setOnTouchListener(this);
if (!mOptions.noButton && mEndButton.getParent() == null) {
RelativeLayout.LayoutParams lps = getConfigOptions().buttonLayoutParams;
if (lps == null) {
lps = (LayoutParams) generateDefaultLayoutParams();
lps.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
lps.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
int margin = ((Number) (mMetricScale * 12)).intValue();
lps.setMargins(margin, margin, margin, margin);
}
mEndButton.setLayoutParams(lps);
mEndButton.setText(
mButtonText != null ? mButtonText : getResources().getString(R.string.ok));
if (!mHasCustomClickListener) {
mEndButton.setOnClickListener(this);
}
addView(mEndButton);
}
}
/**
* @deprecated Use setShowcase() with the target ShowcaseView.NONE
*/
@Deprecated
public void setShowcaseNoView() {
setShowcasePosition(1000000, 1000000);
}
/**
* Set the view to showcase
*
* @param view The {@link View} to showcase.
* @deprecated Use setShowcase with a {@link com.espian.showcaseview.targets.ViewTarget}
*/
@Deprecated
public void setShowcaseView(final View view) {
if (mIsRedundant || view == null) {
mIsRedundant = true;
return;
}
mIsRedundant = false;
view.post(new Runnable() {
@Override
public void run() {
//init();
Point viewPoint = Calculator.getShowcasePointFromView(view, getConfigOptions());
setShowcasePosition(viewPoint);
invalidate();
}
});
}
/**
* @deprecated This will soon become private. Use setShowcase with a {@link com.espian.showcaseview.targets.PointTarget}
*/
@Deprecated
public void setShowcasePosition(Point point) {
setShowcasePosition(point.x, point.y);
}
/**
* Set a specific position to showcase
*
* @param x X co-ordinate
* @param y Y co-ordinate
* @deprecated use setShowcase with a PointTarget
*/
@Deprecated
public void setShowcasePosition(int x, int y) {
if (mIsRedundant) {
return;
}
mShowcaseX = x;
mShowcaseY = y;
//init();
invalidate();
}
public void setShowcase(final Target target) {
setShowcase(target, false);
}
public void setShowcase(final Target target, final boolean animate) {
postDelayed(new Runnable() {
@Override
public void run() {
Point targetPoint = target.getPoint();
if (targetPoint != null) {
mHasNoTarget = false;
if (animate) {
Animator animator = PointAnimator.ofPoints(ShowcaseView.this, targetPoint);
animator.setDuration(getConfigOptions().fadeInDuration);
animator.setInterpolator(INTERPOLATOR);
animator.start();
} else {
setShowcasePosition(targetPoint);
}
} else {
mHasNoTarget = true;
invalidate();
}
}
}, 100);
}
public boolean hasShowcaseView() {
return (mShowcaseX != 1000000 && mShowcaseY != 1000000) || !mHasNoTarget;
}
public void setShowcaseX(int x) {
setShowcasePosition(x, mShowcaseY);
}
public void setShowcaseY(int y) {
setShowcasePosition(mShowcaseX, y);
}
public int getShowcaseX() {
return mShowcaseX;
}
public int getShowcaseY() {
return mShowcaseY;
}
public void setShowcaseItem(final int itemType, final int actionItemId,
final Activity activity) {
post(new Runnable() {
@Override
public void run() {
BaseReflector reflector = BaseReflector.getReflectorForActivity(activity);
ViewParent p = reflector.getActionBarView(); //ActionBarView
ActionBarViewWrapper wrapper = new ActionBarViewWrapper(p);
switch (itemType) {
case ITEM_ACTION_HOME:
setShowcase(new ViewTarget(reflector.getHomeButton()));
//setShowcaseView(reflector.getHomeButton());
break;
case ITEM_SPINNER:
setShowcase(new ViewTarget(wrapper.getSpinnerView()));
//setShowcaseView(wrapper.getSpinnerView());
break;
case ITEM_TITLE:
setShowcase(new ViewTarget(wrapper.getTitleView()));
//setShowcaseView(wrapper.getTitleView());
break;
case ITEM_ACTION_ITEM:
setShowcase(new ViewTarget(wrapper.getActionItem(actionItemId)));
//setShowcaseView(wrapper.getActionItem(actionItemId));
break;
case ITEM_ACTION_OVERFLOW:
View overflow = wrapper.getOverflowView();
// This check essentially checks if we are on a device with a legacy menu key
if (overflow != null) {
setShowcase(new ViewTarget(wrapper.getOverflowView()));
//setShowcaseView(wrapper.getOverflowView());
} else {
setShowcase(new PointTarget(getLegacyOverflowPoint()));
//setShowcasePosition(getLegacyOverflowPoint());
}
break;
default:
Log.e("TAG", "Unknown item type");
}
}
});
}
/**
* Gets the bottom centre of the screen, where a legacy menu would pop up
*/
private Point getLegacyOverflowPoint() {
return new Point(getLeft() + getWidth() / 2, getBottom());
}
/**
* Override the standard button click event
*
* @param listener Listener to listen to on click events
*/
public void setOnButtonClickListener(OnClickListener listener) {
if (mIsRedundant) {
return;
}
if (mEndButton != null) {
mEndButton.setOnClickListener(listener != null ? listener : this);
}
mHasCustomClickListener = true;
}
protected void performButtonClick() {
mEndButton.performClick();
}
public void setOnShowcaseEventListener(OnShowcaseEventListener listener) {
if (listener != null) {
mEventListener = listener;
} else {
mEventListener = OnShowcaseEventListener.NONE;
}
}
public void setButtonText(CharSequence text) {
if (mEndButton != null) {
mEndButton.setText(text);
}
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void setHardwareAccelerated(boolean accelerated) {
if (accelerated) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
if (isHardwareAccelerated()) {
Paint hardwarePaint = new Paint();
hardwarePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.OVERLAY));
setLayerType(LAYER_TYPE_HARDWARE, hardwarePaint);
} else {
setLayerType(LAYER_TYPE_SOFTWARE, null);
}
} else {
setDrawingCacheEnabled(true);
}
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
setLayerType(LAYER_TYPE_SOFTWARE, null);
} else {
setDrawingCacheEnabled(true);
}
}
}
@Override
protected void dispatchDraw(Canvas canvas) {
if (mShowcaseX < 0 || mShowcaseY < 0 || mIsRedundant) {
super.dispatchDraw(canvas);
return;
}
boolean recalculatedCling = mShowcaseDrawer.calculateShowcaseRect(mShowcaseX, mShowcaseY);
boolean recalculateText = recalculatedCling || mAlteredText;
mAlteredText = false;
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.HONEYCOMB && !mHasNoTarget) {
Path path = new Path();
path.addCircle(mShowcaseX, mShowcaseY, mShowcaseRadius, Path.Direction.CW);
canvas.clipPath(path, Op.DIFFERENCE);
}
//Draw background color
canvas.drawColor(mBackgroundColor);
// Draw the showcase drawable
if (!mHasNoTarget) {
mShowcaseDrawer.drawShowcase(canvas, mShowcaseX, mShowcaseY, mScaleMultiplier, mShowcaseRadius);
}
// Draw the text on the screen, recalculating its position if necessary
if (recalculateText) {
mTextDrawer.calculateTextPosition(canvas.getWidth(), canvas.getHeight(), this);
}
mTextDrawer.draw(canvas, recalculateText);
super.dispatchDraw(canvas);
}
/**
* Adds an animated hand performing a gesture.
* All parameters passed to this method are relative to the center of the showcased view.
* @param offsetStartX x-offset of the start position
* @param offsetStartY y-offset of the start position
* @param offsetEndX x-offset of the end position
* @param offsetEndY y-offset of the end position
* @see com.espian.showcaseview.ShowcaseView#animateGesture(float, float, float, float, boolean)
*/
public void animateGesture(float offsetStartX, float offsetStartY, float offsetEndX,
float offsetEndY) {
animateGesture(offsetStartX, offsetStartY, offsetEndX, offsetEndY, false);
}
/**
* Adds an animated hand performing a gesture.
* @param startX x-coordinate or x-offset of the start position
* @param startY y-coordinate or x-offset of the start position
* @param endX x-coordinate or x-offset of the end position
* @param endY y-coordinate or x-offset of the end position
* @param absoluteCoordinates If true, this will use absolute coordinates instead of coordinates relative to the center of the showcased view
*/
public void animateGesture(float startX, float startY, float endX,
float endY, boolean absoluteCoordinates) {
mHandy = ((LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE))
.inflate(R.layout.handy, null);
addView(mHandy);
moveHand(startX, startY, endX, endY, absoluteCoordinates, new AnimationEndListener() {
@Override
public void onAnimationEnd() {
removeView(mHandy);
}
});
}
private void moveHand(float startX, float startY, float endX,
float endY, boolean absoluteCoordinates, AnimationEndListener listener) {
AnimationUtils.createMovementAnimation(mHandy, absoluteCoordinates?0:mShowcaseX,
absoluteCoordinates?0:mShowcaseY,
startX, startY,
endX, endY,
listener).start();
}
@TargetApi(Build.VERSION_CODES.GINGERBREAD)
@Override
public void onClick(View view) {
// If the type is set to one-shot, store that it has shot
if (mOptions.shotType == TYPE_ONE_SHOT) {
SharedPreferences internal = getContext()
.getSharedPreferences(PREFS_SHOWCASE_INTERNAL, Context.MODE_PRIVATE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
internal.edit().putBoolean("hasShot" + getConfigOptions().showcaseId, true).apply();
} else {
internal.edit().putBoolean("hasShot" + getConfigOptions().showcaseId, true)
.commit();
}
}
hide();
}
public void hide() {
mEventListener.onShowcaseViewHide(this);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB
&& getConfigOptions().fadeOutDuration > 0) {
fadeOutShowcase();
} else {
setVisibility(View.GONE);
mEventListener.onShowcaseViewDidHide(this);
}
}
private void fadeOutShowcase() {
AnimationUtils.createFadeOutAnimation(this, new AnimationEndListener() {
@Override
public void onAnimationEnd() {
setVisibility(View.GONE);
mEventListener.onShowcaseViewDidHide(ShowcaseView.this);
}
}).start();
}
public void show() {
mEventListener.onShowcaseViewShow(this);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB
&& getConfigOptions().fadeInDuration > 0) {
fadeInShowcase();
} else {
setVisibility(View.VISIBLE);
}
}
private void fadeInShowcase() {
AnimationUtils.createFadeInAnimation(this, getConfigOptions().fadeInDuration,
new AnimationStartListener() {
@Override
public void onAnimationStart() {
setVisibility(View.VISIBLE);
}
}).start();
}
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
float xDelta = Math.abs(motionEvent.getRawX() - mShowcaseX);
float yDelta = Math.abs(motionEvent.getRawY() - mShowcaseY);
double distanceFromFocus = Math.sqrt(Math.pow(xDelta, 2) + Math.pow(yDelta, 2));
if (MotionEvent.ACTION_UP == motionEvent.getAction() &&
mOptions.hideOnClickOutside && distanceFromFocus > mShowcaseRadius) {
this.hide();
return true;
}
return mOptions.block && distanceFromFocus > mShowcaseRadius;
}
/**
* @deprecated Use setScaleMultiplier
*/
@Deprecated
public void setShowcaseIndicatorScale(float scaleMultiplier) {
setScaleMultiplier(scaleMultiplier);
}
public void setText(int titleTextResId, int subTextResId) {
String titleText = getContext().getResources().getString(titleTextResId);
String subText = getContext().getResources().getString(subTextResId);
setText(titleText, subText);
}
public void setText(String titleText, String subText) {
mTextDrawer.setTitle(titleText);
mTextDrawer.setDetails(subText);
mAlteredText = true;
invalidate();
}
/**
* Get the ghostly gesture hand for custom gestures
*
* @return a View representing the ghostly hand
*/
public View getHand() {
final View mHandy = ((LayoutInflater) getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.handy, null);
addView(mHandy);
AnimationUtils.hide(mHandy);
return mHandy;
}
/**
* Point to a specific view
* @param view The {@link View} to Showcase
* @deprecated use pointTo(Target)
*/
@Deprecated
public void pointTo(View view) {
float x = AnimationUtils.getX(view) + view.getWidth() / 2;
float y = AnimationUtils.getY(view) + view.getHeight() / 2;
pointTo(x, y);
}
/**
* Point to a specific point on the screen
*
* @param x X-coordinate to point to
* @param y Y-coordinate to point to
* @deprecated use pointTo(Target)
*/
@Deprecated
public void pointTo(float x, float y) {
mHandy = getHand();
AnimationUtils.createMovementAnimation(mHandy, x, y).start();
}
/**
* Point to a specific point on the screen
* @param target The target to point to
*/
public void pointTo(final Target target) {
post(new Runnable() {
@Override
public void run() {
mHandy = getHand();
Point targetPoint = target.getPoint();
AnimationUtils.createMovementAnimation(mHandy, targetPoint.x,
targetPoint.y).start();
}
});
}
protected void setConfigOptions(ConfigOptions options) {
mOptions = options;
}
public ConfigOptions getConfigOptions() {
// Make sure that this method never returns null
if (mOptions == null) {
return mOptions = new ConfigOptions();
}
return mOptions;
}
/**
* Quick method to insert a ShowcaseView into an Activity
*
* @param viewToShowcase View to showcase
* @param activity Activity to insert into
* @param title Text to show as a title. Can be null.
* @param detailText More detailed text. Can be null.
* @param options A set of options to customise the ShowcaseView
* @return the created ShowcaseView instance
* @deprecated use insertShowcaseView with {@link Target}
*/
@Deprecated
public static ShowcaseView insertShowcaseView(View viewToShowcase, Activity activity,
String title,
String detailText, ConfigOptions options) {
ShowcaseView sv = new ShowcaseView(activity);
if (options != null) {
sv.setConfigOptions(options);
}
if (sv.getConfigOptions().insert == INSERT_TO_DECOR) {
((ViewGroup) activity.getWindow().getDecorView()).addView(sv);
} else {
((ViewGroup) activity.findViewById(android.R.id.content)).addView(sv);
}
sv.setShowcaseView(viewToShowcase);
sv.setText(title, detailText);
return sv;
}
/**
* Quick method to insert a ShowcaseView into an Activity
*
* @param viewToShowcase View to showcase
* @param activity Activity to insert into
* @param title Text to show as a title. Can be null.
* @param detailText More detailed text. Can be null.
* @param options A set of options to customise the ShowcaseView
* @return the created ShowcaseView instance
* @deprecated use insertShowcaseView with {@link Target}
*/
@Deprecated
public static ShowcaseView insertShowcaseView(View viewToShowcase, Activity activity, int title,
int detailText, ConfigOptions options) {
ShowcaseView sv = new ShowcaseView(activity);
if (options != null) {
sv.setConfigOptions(options);
}
if (sv.getConfigOptions().insert == INSERT_TO_DECOR) {
((ViewGroup) activity.getWindow().getDecorView()).addView(sv);
} else {
((ViewGroup) activity.findViewById(android.R.id.content)).addView(sv);
}
sv.setShowcaseView(viewToShowcase);
sv.setText(title, detailText);
return sv;
}
/**
* @deprecated use insertShowcaseView with {@link Target}
*/
@Deprecated
public static ShowcaseView insertShowcaseView(int showcaseViewId, Activity activity,
String title, String detailText, ConfigOptions options) {
View v = activity.findViewById(showcaseViewId);
if (v != null) {
return insertShowcaseView(v, activity, title, detailText, options);
}
return null;
}
/**
* @deprecated use insertShowcaseView with {@link Target}
*/
@Deprecated
public static ShowcaseView insertShowcaseView(int showcaseViewId, Activity activity, int title,
int detailText, ConfigOptions options) {
View v = activity.findViewById(showcaseViewId);
if (v != null) {
return insertShowcaseView(v, activity, title, detailText, options);
}
return null;
}
/**
* @deprecated use insertShowcaseView with {@link Target}
*/
@Deprecated
public static ShowcaseView insertShowcaseView(int x, int y, Activity activity, String title,
String detailText, ConfigOptions options) {
ShowcaseView sv = new ShowcaseView(activity);
if (options != null) {
sv.setConfigOptions(options);
}
if (sv.getConfigOptions().insert == INSERT_TO_DECOR) {
((ViewGroup) activity.getWindow().getDecorView()).addView(sv);
} else {
((ViewGroup) activity.findViewById(android.R.id.content)).addView(sv);
}
sv.setShowcasePosition(x, y);
sv.setText(title, detailText);
return sv;
}
/**
* @deprecated use insertShowcaseView with {@link Target}
*/
@Deprecated
public static ShowcaseView insertShowcaseView(int x, int y, Activity activity, int title,
int detailText, ConfigOptions options) {
ShowcaseView sv = new ShowcaseView(activity);
if (options != null) {
sv.setConfigOptions(options);
}
if (sv.getConfigOptions().insert == INSERT_TO_DECOR) {
((ViewGroup) activity.getWindow().getDecorView()).addView(sv);
} else {
((ViewGroup) activity.findViewById(android.R.id.content)).addView(sv);
}
sv.setShowcasePosition(x, y);
sv.setText(title, detailText);
return sv;
}
/**
* @deprecated use insertShowcaseView with {@link Target}
*/
@Deprecated
public static ShowcaseView insertShowcaseView(View showcase, Activity activity) {
return insertShowcaseView(showcase, activity, null, null, null);
}
/**
* Quickly insert a ShowcaseView into an Activity, highlighting an item.
*
* @param type the type of item to showcase (can be ITEM_ACTION_HOME,
* ITEM_TITLE_OR_SPINNER, ITEM_ACTION_ITEM or ITEM_ACTION_OVERFLOW)
* @param itemId the ID of an Action item to showcase (only required for ITEM_ACTION_ITEM
* @param activity Activity to insert the ShowcaseView into
* @param title Text to show as a title. Can be null.
* @param detailText More detailed text. Can be null.
* @param options A set of options to customise the ShowcaseView
* @return the created ShowcaseView instance
* @deprecated use insertShowcaseView with {@link Target}
*/
@Deprecated
public static ShowcaseView insertShowcaseViewWithType(int type, int itemId, Activity activity,
String title, String detailText, ConfigOptions options) {
ShowcaseView sv = new ShowcaseView(activity);
if (options != null) {
sv.setConfigOptions(options);
}
if (sv.getConfigOptions().insert == INSERT_TO_DECOR) {
((ViewGroup) activity.getWindow().getDecorView()).addView(sv);
} else {
((ViewGroup) activity.findViewById(android.R.id.content)).addView(sv);
}
sv.setShowcaseItem(type, itemId, activity);
sv.setText(title, detailText);
return sv;
}
/**
* Quickly insert a ShowcaseView into an Activity, highlighting an item.
*
* @param type the type of item to showcase (can be ITEM_ACTION_HOME,
* ITEM_TITLE_OR_SPINNER, ITEM_ACTION_ITEM or ITEM_ACTION_OVERFLOW)
* @param itemId the ID of an Action item to showcase (only required for ITEM_ACTION_ITEM
* @param activity Activity to insert the ShowcaseView into
* @param title Text to show as a title. Can be null.
* @param detailText More detailed text. Can be null.
* @param options A set of options to customise the ShowcaseView
* @return the created ShowcaseView instance
*/
@Deprecated
public static ShowcaseView insertShowcaseViewWithType(int type, int itemId, Activity activity,
int title, int detailText, ConfigOptions options) {
ShowcaseView sv = new ShowcaseView(activity);
if (options != null) {
sv.setConfigOptions(options);
}
if (sv.getConfigOptions().insert == INSERT_TO_DECOR) {
((ViewGroup) activity.getWindow().getDecorView()).addView(sv);
} else {
((ViewGroup) activity.findViewById(android.R.id.content)).addView(sv);
}
sv.setShowcaseItem(type, itemId, activity);
sv.setText(title, detailText);
return sv;
}
@Deprecated
public static ShowcaseView insertShowcaseView(int x, int y, Activity activity) {
return insertShowcaseView(x, y, activity, null, null, null);
}
/**
* Internal insert method so all inserts are routed through one method
*/
private static ShowcaseView insertShowcaseViewInternal(Target target, Activity activity, String title,
String detail, ConfigOptions options) {
ShowcaseView sv = new ShowcaseView(activity);
sv.setConfigOptions(options);
if (sv.getConfigOptions().insert == INSERT_TO_DECOR) {
((ViewGroup) activity.getWindow().getDecorView()).addView(sv);
} else {
((ViewGroup) activity.findViewById(android.R.id.content)).addView(sv);
}
sv.setShowcase(target);
sv.setText(title, detail);
return sv;
}
public static ShowcaseView insertShowcaseView(Target target, Activity activity) {
return insertShowcaseViewInternal(target, activity, null, null, null);
}
public static ShowcaseView insertShowcaseView(Target target, Activity activity, String title, String detail) {
return insertShowcaseViewInternal(target, activity, title, detail, null);
}
public static ShowcaseView insertShowcaseView(Target target, Activity activity, int title, int detail) {
return insertShowcaseViewInternal(target, activity, activity.getString(title), activity.getString(detail), null);
}
public static ShowcaseView insertShowcaseView(Target target, Activity activity, String title, String detail, ConfigOptions options) {
return insertShowcaseViewInternal(target, activity, title, detail, options);
}
public static ShowcaseView insertShowcaseView(Target target, Activity activity, int title, int detail, ConfigOptions options) {
return insertShowcaseViewInternal(target, activity, activity.getString(title), activity.getString(detail), options);
}
public static class ConfigOptions {
public boolean block = true, noButton = false;
public boolean hideOnClickOutside = false;
/**
* Does not work with the {@link ShowcaseViews} class as it does not make sense (only with
* {@link ShowcaseView}).
* @deprecated not compatible with Target API
*/
@Deprecated
public int insert = INSERT_TO_DECOR;
/**
* If you want to use more than one Showcase with the {@link ConfigOptions#shotType} {@link
* ShowcaseView#TYPE_ONE_SHOT} in one Activity, set a unique value for every different
* Showcase you want to use.
*/
public int showcaseId = 0;
/**
* If you want to use more than one Showcase with {@link ShowcaseView#TYPE_ONE_SHOT} in one
* Activity, set a unique {@link ConfigOptions#showcaseId} value for every different
* Showcase you want to use. If you want to use this in the {@link ShowcaseViews} class, you
* need to set a custom showcaseId for each {@link ShowcaseView}.
*/
public int shotType = TYPE_NO_LIMIT;
/**
* Default duration for fade in animation. Set to 0 to disable.
*/
public int fadeInDuration = AnimationUtils.DEFAULT_DURATION;
/**
* Default duration for fade out animation. Set to 0 to disable.
*/
public int fadeOutDuration = AnimationUtils.DEFAULT_DURATION;
/**
* Allow custom positioning of the button within the showcase view.
*/
public LayoutParams buttonLayoutParams = null;
/**
* Whether the text should be centered or stretched in the available space
*/
public boolean centerText = false;
}
public float getScaleMultiplier() {
return mScaleMultiplier;
}
public void setScaleMultiplier(float scaleMultiplier) {
this.mScaleMultiplier = scaleMultiplier;
}
}